package com.itany.corejava.code11_io.字节流;


import java.io.*;
import java.util.Date;

/**
 * @author 石小俊
 * @date 2023年05月10日 15:59
 */
public class Test01_FileInputStream {

    public static void main(String[] args) {
        test03();
    }

    /**
     * 基本用法:每次读取一个字节
     */
    public static void test01() {
        FileInputStream in = null;
        try {
            // 其参数可以是一个文件路径+文件名,支持绝对路径与相对路径
            // in = new FileInputStream("a.txt");
            // 参数也可以是一个File对象
            File file = new File("a.txt");
            in = new FileInputStream(file);

            // 将文件内容读取到程序中,在控制台打印出来
            // read():从此输入流中读取一个数据字节
            // 返回int类型的字节值,如果读取到末尾,则返回-1
            // int data = in.read();
            // System.out.println(data);
            // 读取的数据返回的是byte类型,因此可以将其强转成char
            // 此时如果读取的是中文,一定出现乱码
            // 中文根据编码不同占2-3个字节,但是读取的只有一个字节
            // System.out.println((char)data);
            // data = in.read();
            // System.out.println((char)data);

            // 由于每次只读取一个字节,如果一个个的写太麻烦
            // 通过循环一直读取,直到返回为-1为止
            // int data = in.read();
            // while(data != -1){
            //     System.out.println((char)data);
            //     data = in.read();
            // }

            // 简写方式
            int data = -1;
            while ((data = in.read()) != -1) {
                System.out.println((char) data);
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭输入流,释放资源
            // 只要打开了外部资源,最终都必须关闭
            // 例如:文件、数据库连接、网络连接
            // 遵循谁开谁关的原则
            // 在关闭的时候可能由于异常导致压根没打开,这时候不需要关闭
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 其他用法:JDK7新语法自动释放资源、同时读取多个字节
     */
    public static void test02() {

        // 在DK7引入了一个新语法,叫做try-with-resource
        // 用于自动关闭外部资源,不需要写finally,可以简化关闭的操作
        try (
                // 将所有需要关闭的资源操作,在try语句的括号中实现
                // 此处只能创建实现了AutoCloseable接口的对象
                FileInputStream in = new FileInputStream("corejava/src/a.txt");
                // 如果在此处创建的对象没有实现AutoCloseable接口
                // 则直接报错
                // 因为这种资源不需要释放
                // Date date = new Date();
                // 简单来讲,在此处创建的对象会自动释放资源
        ) {
            // in = new FileInputStream("a.txt");

            // 每次只读取一个字节,效率太低,并且容器出现问题
            // 因此,可以设置每次读取多个字节,减少读取次数,提高效率
            // byte[] b = new byte[3];
            // 从此输入流中将最多b.length个字节的数据读入一个byte数组中
            // 即:将读取的多个字节传递到参数byte数组中
            // 此时的返回值表示读取的字节数
            // int data = in.read(b);
            // System.out.println(data);
            // System.out.println(new String(b));

            // 简写
            // 读取的时候可以将字节数组长度稍微放大点,防止出现中文乱码
            byte[] b = new byte[1024];
            int data = -1;
            while ((data = in.read(b)) != -1) {
                // 可以通过字符串构造方法将指定的字节数组转换成字符串
                // System.out.println(new String(b));
                // 将指定的字节数组从指定索引开始转换,一直转换指定的长度
                // read方法的返回值表示的是读取的字节数量
                // 可以从起始位置开始转换,一直转换返回值的长度
                // 参数一:需要转换的字节数组
                // 参数二:从哪一个索引位置开始转换
                // 参数三:转换多少个字节
                System.out.println(new String(b, 0, data));
            }


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 加载字节流时路径的不同用法
     */
    public static void test03() {
        try (
                // 支持绝对路径
                // FileInputStream in = new FileInputStream("E:/itany/a.txt");
                InputStream in = new FileInputStream("E:/itany/a.txt");
                // 支持相对路径,相对的Project下的根目录
                FileInputStream in2 = new FileInputStream("a.txt");
                // 支持类加载路径,此处为当前Module的src目录作为根目录
                InputStream in3 = Test01_FileInputStream.class.getClassLoader().getResourceAsStream("a.txt");
        ) {
            byte[] b = new byte[1024];
            int data = -1;
            while ((data = in3.read(b)) != -1) {
                System.out.println(new String(b, 0, data));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
